//
//  ListeningNode.cpp
//  Simulation
//
//  Created by Christopher Kemsley on 3/3/12.
//  Copyright (c) 2012 iAppolopolis. All rights reserved.
//

#include "EveryModel.hpp"

#include "EventMonitor.hpp"
#include "ModuleFactory.hpp"
#include "TransmissionBroker.hpp"

#include "BroadcastData.hpp"
#include "Log.hpp"

#include "SimulationParameters.hpp"

using namespace Sim ;



struct	ListeningModel_sensingSettings : public EveryModelSettings
{
	
	
	
	ListeningModel_sensingSettings	( std::string const & name )
	:	EveryModelSettings(name)
		{
		
		}
} ;




struct	ListeningModel_sensing : public EveryModel<ListeningModel_sensingSettings> , public ReceiverDelegate , public TransmitterDelegate
{
	ListeningModel_sensing	( ModelVariant const & identity )
	:	EveryModel<ListeningModel_sensingSettings>	( identity )
	,	mProfile		( mConfig.location , mConfig.txRange )
	,	mReceiver		( mConfig.identifier[0] , mProfile , *this )
	,	mTransmitter	( mConfig.identifier[0] , *this )
		{
		
		}
	
	virtual ~ListeningModel_sensing ()
		{
		
		}
	
	
	
	
	/* Structure */
	
	TransmitterProfile	mProfile ;
	Receiver			mReceiver ;
	Transmitter			mTransmitter ;
	DP<Timer>			mSendCTSTimer ;
	
	
	
	
	virtual void	receiveDidComplete	( Message * message )
		{
		BroadcastInfo::Type		messageType ;
		DeviceID				sender ;
		DeviceID				target ;
		
		decodeBroadcast ( message->bytes , messageType , sender , target ) ;
		
		if ( target == mConfig.identifier[0] )
			{
			switch ( messageType )
				{
					case BroadcastInfo::kTypeControl : {
						ControlBroadcastInfo::SubType	subtype ;
						decodeControl ( message->bytes , subtype ) ;
						_handleControlBroadcast ( message , subtype , sender ) ;
					} break ;
					
					case BroadcastInfo::kTypeData : {
						Log::states("ListeningModel_sensing") << mConfig.identifier << ": Received data" ;
						
						Invocation * i = ObjectContextInvocation<ListeningModel_sensing,DeviceID>::invocation ( this , &ListeningModel_sensing::_sendACK , sender ) ;
						Interval interval = SimulationParameters::shared().SIFSDuration ;
						Log::states("ListeningModel_sensing") << mConfig.identifier << ": Waiting " << interval ;
						mSendCTSTimer << new Timer ( interval , i ) ;
					} break ;
				}
			}
		}
	void	_handleControlBroadcast	( Message * message , ControlBroadcastInfo::SubType type , DeviceID const & sender )
		{
		switch ( type )
			{
				case ControlBroadcastInfo :: kSubTypeRTS : {
					Log::states("ListeningModel_sensing") << mConfig.identifier << ": Received RTS" ;
					
					Invocation * i = ObjectContextInvocation<ListeningModel_sensing,DeviceID>::invocation ( this , &ListeningModel_sensing::_sendCTS , sender ) ;
					Interval interval = SimulationParameters::shared().SIFSDuration ;
					Log::states("ListeningModel_sensing") << mConfig.identifier << ": Waiting " << interval ;
					mSendCTSTimer << new Timer ( interval , i ) ;
				} break ;
				
				case ControlBroadcastInfo :: kSubTypeCTS : {
					Log::states("ListeningModel_sensing") << mConfig.identifier << ": Received CTS" ;
				} break ;
				
				case ControlBroadcastInfo :: kSubTypeACK : {
					
				} break ;
			}
		}
	
	void	_sendCTS ( DeviceID const & sender )
		{
		Log::states("ListeningModel_sensing") << mConfig.identifier << ": Sending CTS" ;
		
		mSendCTSTimer << 0 ;
		
		mReceiver.disable() ;
		Length	length	=	SimulationParameters::shared().controlPacketSize ;
		Byte	buffer		[length] ;
		
		encodeCTS ( buffer , length , mConfig.identifier[0] , sender ) ;
		
		mTransmitter . transmit ( buffer,length , sender , mProfile ) ;
		}
	void	_sendACK ( DeviceID const & sender )
		{
		Log::states("ListeningModel_sensing") << mConfig.identifier << ": Sending ACK" ;
		
		mSendCTSTimer << 0 ;
		
		mReceiver.disable() ;
		Length	length	=	SimulationParameters::shared().controlPacketSize ;
		Byte	buffer		[length] ;
		
		encodeACK ( buffer , length , mConfig.identifier[0] , sender ) ;
		
		mTransmitter . transmit ( buffer,length , sender , mProfile ) ;
		}
	
	virtual void	transmissionDidComplete ()
		{
		Log::states("ListeningModel_sensing") << mConfig.identifier << ": DONE transmitting" ;
		
		mReceiver.enable() ;
		}
	
	
	
} ;




TypedModuleMaker<ListeningModel_sensing> _ListeningModel_sensing ( "csma_ca.sensing.passive" ) ;
